<?php
namespace App\Libs\Base;
use \App\Libs\Exception\RuntimeException;
use \App\Libs\Log\Logger;
abstract class BaseAction
{
    protected $ip;
    protected $di;
    protected $session;
    protected $request;
    protected $response;
    protected $declareView = 'json';
    protected $needLogin = FALSE;
	protected $needSignatrue = FALSE;
    public function __construct($di) {
        $this->ip = $this->getIP();
        $this->di = $di;
        $this->request = $di->get('request');
    }

    final public function run() {
        try {
            $this->beforeRun();
            $this->beforeExecute();
            $this->response = $this->execute();
        } catch(RuntimeException $re) {
            $msg = '[exception: ' . get_class($re) . '] ';
            $msg .= '[code: ' . $re->getCode() . '] [' . $re->getMessage() . ']';
            Logger::error('runtime', $msg);
            switch ($this->declareView) {
            case 'json':
                $this->response = \App\Libs\Views\Json::view($re->getCode(), $re->getMessage());
                break;
            case 'smarty':
                $this->response = \App\Libs\Views\Smarty::view(
                    array(
                        'islogin' => ! empty($this->session),
                        'username' => ! empty($this->session) ? $this->session->nickname : '',
                        ),
                    'html/passport/login.tpl.html');
                break;
			case 'twig':
                $this->response = \App\Libs\Views\Twig::view(
                    array(
                        'islogin' => ! empty($this->session),
                        'username' => ! empty($this->session) ? $this->session->nickname : '',
                        ),
                    'html/passport/login.tpl.html');
                break;
            }

        }catch (\Exception $e) { // 系统级错误
			$msg = '[exception: ' . get_class($e) . '] ';
			$msg .= '[code: ' . $e->getCode() . '] [' . $e->getMessage() . ']';
			Logger::error('exception', $msg);
			// need rewrite
			if (DEBUG) {
				$this->response = $e;
				$this->declareView = 'exception';
			} else {
				switch ($this->declareView) {
				case 'json':
					$this->response = \App\Libs\Views\Json::view($e->getCode(), $e->getMessage());
					break;
				case 'smarty':
					$this->response = \App\Libs\Views\Smarty::view(
						array(),
						'html/error/error.tpl.html'
					);
					break;
				}
			}
        } finally {
            $this->_formatView();
            if (function_exists('fastcgi_finish_request')) {
                fastcgi_finish_request();
            }
            $this->afterRun();
        }
    }

    protected function beforeRun() {
        $this->declareView = 'json';
        $this->needLogin = FALSE;
    }

    protected function beforeExecute() {
        if ($this->needLogin && empty($this->di->getSession())) {
            throw RuntimeException::instance(Constant::UNLOGIN);
        }
		// 签名校验
		if ($this->needSignatrue && !$this->validateSignatrue()) {
			throw RuntimeException::instance(Constant::INVALID_SIGN);
		}
        $this->session = $this->di->getSession();
        if (empty($this->session)) {
            return;
        }

		return;
        // check access
        $rules = $this->accessRules();
        $allow = FALSE;
        foreach ($rules as $permit => $rule) {
            $hit = $this->checkRulePoint($rule);
            if ($hit && strtolower($permit) === 'deny') {
                throw RuntimeException::instance(constant::DENY);
            } else if ($hit && strtolower($permit) === 'allow') {
                $allow = TRUE;
            }
        }
        if ( ! $allow) {
            throw RuntimeException::instance(constant::DENY);
        }
    }

    private function checkRulePoint($rule) {
        foreach ($rule as $type => $points) {
            switch ($type) {
                case 'roles':
                    $checkPoint = $this->session->role_id;
                    break;
                case 'users':
                    $checkPoint = $this->session->nickname;
                    break;
                default:
                    $checkPoint = '*';
                    break;
            }
            $hit = in_array('*', $points);
            if ( ! $hit) {
                $hit = in_array($checkPoint, $points);
            }
            if ($hit) {
                return TRUE;
            }
        }
        return FALSE;
    }

    /**
     *
     *  allow => array(
     *   roles => array(id),
     *   users => array(name1,name2,name3)
     *
     */
    protected function accessRules() {
        return array(
            'allow' => array(
                'roles' => array('*'),
                'users' => array('*'),
            ),
            'deny' => array(),
        );
    }

    // log collect ect
    protected function afterRun() {
    }

    final protected function getPagination($defaultPage = 1, $defaultSize = 30) {
        $curPage = $this->request->get('cur_page');
        $perPage = $this->request->get('per_page');

        $curPage = intval($curPage) < 1 ? $defaultPage : intval($curPage);
        $perPage = intval($perPage) < 1 ? $defaultSize : intval($perPage);
        $perPage > $defaultSize && $perPage = $defaultSize;

        return array(
            'cur_page' => $curPage,
            'per_page' => $perPage,
            'offset' => ($curPage - 1) * $perPage,
            'limit' => $perPage,
        );
    }

    protected abstract function execute();

    private function _formatView() {
        $class = '\\App\\Libs\\Views\\' . ucfirst($this->declareView);
        if (class_exists($class)) {
            $view = new $class();
            if ($view instanceof \App\Libs\Views\View) {
                $result = call_user_func_array(array($view, 'display'), array($this->response));
                return $result;
            }
        }
        $this->response = new \App\Libs\Exception\ViewNotFoundException($this->response);
        $view = new \App\Libs\Views\Exception();
        $result = call_user_func_array(array($view, 'display'), array($this->response));
        return $result;
    }

    private function getIP() {
        return \App\Libs\Helper\Util::getIP();
    }

  

    protected function validateSignatrue() {
        $key = 'MhXkhl(@)(80937)';

        $params = array_merge($_GET, $_POST);
        if (!isset($params['sign'])) {
            return FALSE;
        }
        $sign = $params['sign'];
		$filters = array('_version', '_os', '_channel', '_ts', '_sign', '_url');
		foreach ($filters as $f) {
			unset($params[$f]);
		}

        ksort($params);
		$str = http_build_query($params);
		$str = $key . ':' . $str;
        if ($sign == md5($str)) {
            return TRUE;
        }
        return FALSE;
    }

   
}
